﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;
using System.Drawing;
using EdytorWF.Engine;

namespace EdytorWF.Objects
{
    public class Terrain : IObject
    {
        public float StepX { get; set; }
        public float StepY { get; set; }
        public int ResolutionX { get; set; }
        public int ResolutionY { get; set; }
        public float MaxHeight { get; set; }

        static int count = 0;
        public Vector3 Translation { get; set; }
        public CustomVertex.PositionNormalTextured[] Vertices { get; set; }
        public int[] Indices { get; set; }

        public Terrain(Device d)           // prosty konstruktor
        {
            MyMesh = null;
            Device = d;
            TypeName = "_TERRAIN";
            ObjectName = String.Format("Terrain{0}", count);
            ++count;

            StepX = 1.0f;
            StepY = 1.0f;

            MaxHeight = 30;
            Translation = new Vector3(0, 0, 0);

            Textures = new List<Texture>();

            if (Device != null)
            {
                LoadTexture("..\\..\\Resources\\Textures\\rock.jpg");
                LoadMesh("..\\..\\Resources\\Textures\\terrain.bmp");
            }
        }

        public override void ReloadMesh()
        {
            //LoadMesh("..\\..\\Resources\\Textures\\terrain.bmp");
        }

        public override void ReloadTexture()
        {
            //LoadTexture("..\\..\\Resources\\Textures\\rock.jpg");
        }

        public override void ReloadObject()
        {
            ReloadMesh();
            ReloadTexture();
        }

        public override void Render()                // Rendering obiektu na device
        {
            if (Device != null && MyMesh != null)
            {
                Device.VertexFormat = MyMesh.VertexFormat;   //Ustalamy Format Vertexów
                for (int i = 0; i < ExtendedMaterials.Count; i++)      //EM.Length zawiera liczbę submeshów danego mesha
                {
                    Device.Material = Materials[i];            //każdy submesh ma inny materiał
                    Device.SetTexture(0, Textures[i]);         //i inną teksturę
                    MyMesh.DrawSubset(i);                        //rendering i-tego submesha
                }
            }
        }

        public override void Render(ref Effect effect, string texture, bool with_lights)                // Rendering obiektu na device
        {
            if (Device != null)
            {
                Device.VertexFormat = MyMesh.VertexFormat;   //Ustalamy Format Vertexów
                for (int i = 0; i < ExtendedMaterials.Count; i++)      //EM.Length zawiera liczbę submeshów danego mesha
                {
                    //Device.Material = Materials[i];            //każdy submesh ma inny materiał
                    //Device.SetTexture(0, Textures[i]);         //i inną teksturę
                    MyMesh.DrawSubset(i);                        //rendering i-tego submesha
                }
            }
        }

        public void CreateTerrainFromFile(float StepX, float StepY, float MaxHeight, string Filename)
        {
            if (Device == null)
                return;

            Bitmap b = new Bitmap(Filename);

            float min_x = float.MaxValue, min_y = float.MaxValue, min_z = float.MaxValue;
            float max_x = float.MinValue, max_y = float.MinValue, max_z = float.MinValue;

            int NoX = ResolutionX = b.Size.Width;
            int NoZ = ResolutionY = b.Size.Height;
            int NoV = NoX * NoZ;
            int NoF = (NoX - 1) * (NoZ - 1) * 2 * 3;
            Vertices = new CustomVertex.PositionNormalTextured[NoV];
            int k = 0;
            for (int i = 0; i < NoX; i++)
                for (int j = 0; j < NoZ; j++)
                {
                    Vertices[k].Position = new Vector3(i * StepX - (NoX / 2) * StepX, (float)((float)b.GetPixel(i, j).R / 255) * MaxHeight, j * StepY - (NoZ / 2) * StepY);
                    Vertices[k].Position += Translation;
                    if (min_x > Vertices[k].Position.X)
                    {
                        min_x = Vertices[k].Position.X;
                    }
                    else if (max_x < Vertices[k].Position.X)
                    {
                        max_x = Vertices[k].Position.X;
                    }

                    if (min_y > Vertices[k].Position.Y)
                    {
                        min_y = Vertices[k].Position.Y;
                    }
                    else if (max_y < Vertices[k].Position.Y)
                    {
                        max_y = Vertices[k].Position.Y;
                    }

                    if (min_z > Vertices[k].Position.Z)
                    {
                        min_z = Vertices[k].Position.Z;
                    }
                    else if (max_z < Vertices[k].Position.Z)
                    {
                        max_z = Vertices[k].Position.Z;
                    }

                    Vertices[k].Normal = new Vector3(0, 0, 0);
                    Vertices[k].Tu = i / (float)(NoX - 1);
                    Vertices[k].Tv = j / (float)(NoZ - 1);
                    
                    k++;
                }
            Indices = new int[NoF];

            k = 0;
            for (int i = 1; i < NoX; i++)
                for (int j = 1; j < NoZ; j++)
                {
                    int vec_1 = i * NoZ + j - 1;
                    int vec_2 = (i - 1) * NoZ + j - 1;
                    int vec_3 = (i - 1) * NoZ + j;

                    Indices[k++] = vec_1;
                    Indices[k++] = vec_2;
                    Indices[k++] = vec_3;

                    int vec_4 = i * NoZ + j;
                    int vec_5 = i * NoZ + j - 1;
                    int vec_6 = (i - 1) * NoZ + j;

                    Indices[k++] = vec_4;
                    Indices[k++] = vec_5;
                    Indices[k++] = vec_6; 
                }

            CollisionBox = new BoundingBox(new Vector3(min_x, min_y, min_z), new Vector3(max_x, max_y, max_z));
            MyMesh = new Mesh(NoF, NoV, MeshFlags.Managed | MeshFlags.Use32Bit, CustomVertex.PositionNormalTextured.Format, Device);


            MyMesh.IndexBuffer.SetData(Indices, 0, LockFlags.None);
            MyMesh.VertexBuffer.SetData(Vertices, 0, LockFlags.None);
            MyMesh.ComputeNormals();
            ExtendedMaterials = new List<ExtendedMaterial>();
            ExtendedMaterials.Add(new ExtendedMaterial());
            Materials = new List<Material>();
            Materials.Add(new Material
            {
                Ambient = Color.White,
                Diffuse = Color.White
            });
        }

        public override void LoadTexture(string FileName)
        {
            if (Device == null)
                return;

            TextureFileName = FileName;
            if (Textures != null)
            {
                Textures.Add(TextureLoader.FromFile(Device, TextureFileName));
            }
        }

        public override void LoadMesh(string file_name)
        {
            MeshFileName = file_name;
            CreateTerrainFromFile(StepX, StepY, MaxHeight, MeshFileName);
        }
    }
}
